#include "camera.h"

cCamera g_Camera;

cCamera::cCamera()
{
	m_Speed = CAMERASPEED;
	m_Up = VECUP;
	m_At = VECAT;
	m_Eye = VECEYE;
	SetView();
	SetProj();
	SetViewProj();
}
cCamera::cCamera(VEC3 _Up,VEC3 _Eye,VEC3 _At,float _Speed):
	m_Up(_Up),m_Eye(_Eye),m_At(_At),m_Speed(_Speed)
{
	SetView();
	SetProj();
	SetViewProj();
}
void cCamera::SetView(){
	D3DXMatrixLookAtLH(&m_View,&m_Eye,&m_At,&m_Up);
}
void cCamera::SetProj()
{
	D3DXMatrixPerspectiveFovLH(&m_Proj,D3DX_PI/3,800.0/600.0,1.0f,50000.0f);
}
void cCamera::SetViewProj()
{
	D3DXMatrixMultiply(&m_ViewProj,&m_View,&m_Proj);
	BuildFrustumPlane();
}
void cCamera::SetAxis()
{
	D3DXVec3Normalize(&m_ZAxis,&(m_At-m_Eye));
	D3DXVec3Cross(&m_XAxis,&m_Up,&m_ZAxis);
	D3DXVec3Normalize(&m_XAxis,&m_XAxis);
	D3DXVec3Cross(&m_YAxis,&m_ZAxis,&m_XAxis);
}
void cCamera::NormalizeAxis()
{
	D3DXVec3Normalize(&m_XAxis,&m_XAxis);
	D3DXVec3Normalize(&m_YAxis,&m_YAxis);
	D3DXVec3Normalize(&m_ZAxis,&m_ZAxis);
}
void cCamera::SetXDir(bool XForward)
{
	m_XDir = XForward?1:-1;
}
void cCamera::SetYDir(bool YForward)
{
	m_YDir = YForward?1:-1;
}
void cCamera::SetZDir(bool ZForward)
{
	m_ZDir = ZForward?1:-1;
}
void cCamera::ZForward(float dt)
{
	float dist = m_ZDir*m_Speed*dt;
	SetAxis();
	m_Eye += dist*m_ZAxis;
	m_At = m_Eye + m_ZAxis;
}
void cCamera::YForward(float dt)
{
	float dist = m_YDir*m_Speed*dt;
	SetAxis();
	m_Eye += dist*m_YAxis;
	m_At = m_Eye + m_ZAxis;
}
void cCamera::XForward(float dt)
{
	float dist = m_XDir*m_Speed*dt;
	SetAxis();
	m_Eye += dist*m_XAxis;
	m_At = m_Eye + m_ZAxis;
}
void cCamera::XRotate(float angle)
{
	SetAxis();
	MAT matRotateX;
	D3DXMatrixRotationAxis(&matRotateX,&m_XAxis,angle);
	D3DXVec3TransformCoord(&m_YAxis,&m_YAxis,&matRotateX);
	D3DXVec3Normalize(&m_YAxis,&m_YAxis);
	D3DXVec3Cross(&m_ZAxis,&m_XAxis,&m_YAxis);
	D3DXVec3Normalize(&m_ZAxis,&m_ZAxis);
	D3DXVec3Cross(&m_Up,&m_ZAxis,&m_XAxis);
	D3DXVec3Normalize(&m_Up,&m_Up);
	m_At = m_Eye + m_ZAxis;
	SetView();
	SetViewProj();
}
void cCamera::YRotate(float angle)
{
	SetAxis();

	MAT matRotateY;
	D3DXMatrixRotationAxis(&matRotateY,&m_YAxis,angle);
	D3DXVec3TransformCoord(&m_XAxis,&m_XAxis,&matRotateY);
	D3DXVec3Normalize(&m_XAxis,&m_XAxis);
	D3DXVec3Cross(&m_ZAxis,&m_XAxis,&m_YAxis);
	D3DXVec3Normalize(&m_ZAxis,&m_ZAxis);
	m_At = m_Eye + m_ZAxis;
	SetView();
	SetViewProj();
}
void cCamera::ZRotate(float angle)
{
	SetAxis();
	MAT matRotateZ;
	D3DXMatrixRotationAxis(&matRotateZ,&m_ZAxis,angle);
	D3DXVec3TransformCoord(&m_Up,&m_Up,&matRotateZ);
	m_At = m_Eye + m_ZAxis;
	SetView();
	SetViewProj();
}
void cCamera::CameraXPos(float dt,bool isPositive)
{
	if(isPositive)
		m_Eye.x+=m_Speed*dt;
	else m_Eye.x-=m_Speed*dt;
	SetView();
	SetViewProj();
}
void cCamera::CameraYPos(float dt,bool isPositive)
{
	if(isPositive)
		m_Eye.y+=m_Speed*dt;
	else m_Eye.y-=m_Speed*dt;
	SetView();
	SetViewProj();
}
void cCamera::CameraZPos(float dt,bool isPositive)
{
	if(isPositive)
		m_Eye.z+=m_Speed*dt;
	else m_Eye.z-=m_Speed*dt;
	SetView();
	SetViewProj();
}
void cCamera::AimXPos(float dt,bool isPositive)
{
	if(isPositive)
		m_At.x+=m_Speed*dt;
	else m_At.x-=m_Speed*dt;
	SetView();
	SetViewProj();
}
void cCamera::AimYPos(float dt,bool isPositive)
{
	if(isPositive)
		m_At.y+=m_Speed*dt;
	else m_At.y-=m_Speed*dt;
	SetView();
	SetViewProj();
}
void cCamera::AimZPos(float dt,bool isPositive)
{
	if(isPositive)
		m_At.z+=m_Speed*dt;
	else m_At.z-=m_Speed*dt;
	SetView();
	SetViewProj();
}

void cCamera::BuildFrustumPlane()
{
	D3DXVECTOR4 col0(m_ViewProj(0,0), m_ViewProj(1,0), m_ViewProj(2,0), m_ViewProj(3,0));
	D3DXVECTOR4 col1(m_ViewProj(0,1), m_ViewProj(1,1), m_ViewProj(2,1), m_ViewProj(3,1));
	D3DXVECTOR4 col2(m_ViewProj(0,2), m_ViewProj(1,2), m_ViewProj(2,2), m_ViewProj(3,2));
	D3DXVECTOR4 col3(m_ViewProj(0,3), m_ViewProj(1,3), m_ViewProj(2,3), m_ViewProj(3,3));

	// Planes face inward.
	m_FrustumPlanes[0] = (D3DXPLANE)(col2);        // near
	m_FrustumPlanes[1] = (D3DXPLANE)(col3 - col2); // far
	m_FrustumPlanes[2] = (D3DXPLANE)(col3 + col0); // left

	m_FrustumPlanes[3] = (D3DXPLANE)(col3 - col0); // right
	m_FrustumPlanes[4] = (D3DXPLANE)(col3 - col1); // top
	m_FrustumPlanes[5] = (D3DXPLANE)(col3 + col1); // bottom

	for(int i = 0; i < 6; i++)
		D3DXPlaneNormalize(&m_FrustumPlanes[i],
		&m_FrustumPlanes[i]);

}
bool cCamera::CheckVisible(SPHERE& sphere)
{
	for(int i = 0;i!=6;++i){
		D3DXVECTOR4 center = D3DXVECTOR4(sphere.center.x,sphere.center.y,sphere.center.z,1.0f);
		float dotProduct = D3DXPlaneDot(&m_FrustumPlanes[i],&center);
		if(dotProduct+sphere.radius<=0)
			return false;
	}
	return true;
}


//////////////////////////////////////////////////////////////////////////
//Get Methods For Camera
//////////////////////////////////////////////////////////////////////////
cCamera* GetCamera()
{
	return &g_Camera;
}

D3DXMATRIX GetViewProj()
{
	return g_Camera.GetViewProj();
}
D3DXMATRIX GetView()
{
	return g_Camera.GetView();
}
D3DXMATRIX GetProj()
{
	return g_Camera.GetProj();
}